// ignore_for_file: use_build_context_synchronously

import 'dart:io';

import 'package:aero_frisbee/app/conf/app_env.dart';
import 'package:dio/dio.dart';
import 'package:pretty_dio_logger/pretty_dio_logger.dart';

import 'af_app_err.dart';
import 'dio_interceptors.dart';

class AfHttpUtil {
  static final AfHttpUtil _singleton = AfHttpUtil._();

  // 该类为单例模式
  static AfHttpUtil get instance => _singleton;

  static AfHttpUtil get I => instance;

  static late Dio _dio;

  Dio get dio => _dio;

  AfHttpUtil._() {
    final BaseOptions options = BaseOptions(
      validateStatus: (_) {
        // 不使用http状态码判断状态，使用AdapterInterceptor来处理（适用于标准REST风格）
        return true;
      },
      baseUrl: AppENV.baseUrl,
    );
    _dio = Dio(options);
    addInterceptor(
      HeaderInterceptor(),
    );

    addInterceptor(
      PrettyDioLogger(
          requestHeader: true,
          requestBody: true,
          responseBody: true,
          responseHeader: false,
          error: true,
          compact: true,
          maxWidth: 90),
    );
  }

  /// 添加拦截器
  void addInterceptor(Interceptor interceptor) {
    _dio.interceptors.add(interceptor);
  }

  Future<dynamic> req<T>(
    String path, {
    data,
    Map<String, dynamic>? queryParameters,
    CancelToken? cancelToken,
    Options? options,
    ProgressCallback? onSendProgress,
    ProgressCallback? onReceiveProgress,
  }) async {
    try {
      Response response = await _dio.request(
        path,
        data: data,
        options: options,
        queryParameters: queryParameters,
        cancelToken: cancelToken,
        onSendProgress: onSendProgress,
        onReceiveProgress: onReceiveProgress,
      );
      final code = response.data['code'];
      if (code == 0) {
        return response.data['data'];
      } else {
        throw AfAppErr(
          message: response.data['msg'] ?? 'request is error~',
          type: AppErrorType.service,
          code: '${response.data['code']}',
        );
      }
    } catch (err) {
      if (err is DioException) {
        if (err.type == DioExceptionType.cancel) {
          throw AfAppErr(
              message: 'cancel',
              error: err,
              type: AppErrorType.network,
              code: '201${err.type.index}1');
        } else if (err.type == DioExceptionType.sendTimeout) {
          if (err.error != null) {
            //这块感觉嵌套了，主要是为了与format_interceptor 获取dioError 中 为AppError类型的error
            throw AfAppErr.fromError(err.error);
          } else {
            throw AfAppErr(
                message: 'net work error！',
                error: err,
                type: AppErrorType.network,
                code: '201${err.type.index}2');
          }
        } else if (err.type == DioExceptionType.receiveTimeout) {
          dynamic e = err.error;
          if (e is SocketException) {
            throw AfAppErr(
                message: 'net work error！',
                error: err,
                type: AppErrorType.network,
                code: '201${err.type.index}1');
          } else if (e is HttpException) {
            throw AfAppErr(
                message: 'server work error！',
                error: err,
                type: AppErrorType.network,
                code: '201${err.type.index}2');
          }
          throw AfAppErr(
              message: 'net work error！',
              error: err,
              type: AppErrorType.network,
              code: '201${err.type.index}3');
        } else {
          throw AfAppErr(
              message: 'time out',
              error: err,
              type: AppErrorType.network,
              code: '201${err.type.index}0');
        }
      } else {
        throw AfAppErr.fromError(err);
      }
    }
  }

  Future<T> getParse<T>(
    String path, {
    required T Function(dynamic data) parseJsonFn,
    CancelToken? cancelToken,
    Options? options,
    Map<String, dynamic>? params,
  }) async {
    final ret = await get(path,
        params: params, cancelToken: cancelToken, options: options);
    return parseJsonFn(ret);
  }

  Future<dynamic> get(
    String path, {
    CancelToken? cancelToken,
    Options? options,
    Map<String, dynamic>? params,
  }) async {
    return req(
      path,
      options: options, //contentType 默认为GET
      queryParameters: params,
      cancelToken: cancelToken,
    );
  }

  Future<T> postParse<T>(
    String path, {
    required T Function(dynamic data) parseJsonFn,
    CancelToken? cancelToken,
    Map<String, dynamic>? queryParameters,
    Options? options,
    dynamic params,
  }) async {
    final ret = await post(
      path,
      params: params,
      queryParameters: queryParameters,
      cancelToken: cancelToken,
      options: options,
    );
    return parseJsonFn(ret);
  }

  Future<dynamic> post(
    String path, {
    CancelToken? cancelToken,
    Map<String, dynamic>? queryParameters,
    Options? options,
    dynamic params,
  }) async {
    options ??= Options();
    options.method = "POST";
    return req(
      path,
      data: params,
      queryParameters: queryParameters,
      options: options,
      cancelToken: cancelToken,
    );
  }
}
